package ui;

import info.Conference;
import info.Manuscript;
import io.ConferenceAccess;
import io.ManuscriptAccess;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.text.JTextComponent;

import users.Author;
import users.Role;
import users.User;

/**
 * This panel mimics the layout of the manuscript submission form.  It can
 * double as a form to fill out, and as a display for previously submitted
 * forms.
 * 
 * @author Aaron Chen
 * @version 3/6/2014
 */
@SuppressWarnings("serial")
public class ManuscriptSubmissionPanel extends AbstractForm {
  
  /** The error message to be displayed when the user attempt to submit a 
   * manuscript passed the submission deadline. */
  private static final String ERROR_DEADLINE = "The submission deadline has passed, sorry!";
  
  /** The Manuscript object that this form represents. */
  protected Manuscript my_manuscript;
  
  /** The conference that this manuscript is associated with. */
  protected Conference my_conference;
  
  /** The text field for the author's name. */
  private JTextField my_tf_author;
  
  /** The text field for the author's email. */
  private JTextField my_tf_email;
  
  /** The text field for the name of the conference the manuscript
   * is/was being submitted to. */
  private JTextField my_tf_conference_name;
  
  /** The text field for the categories of the conference the
   * manuscript is/was being submitted to. */
  private JTextField my_tf_conference_category;
  
  /** The text field for the key words used to aid the system's
   * search engine. */
  private JTextField my_tf_key_words;
  
  /** The text field for the manuscript's title. */
  private JTextField my_tf_manuscript_title;
  
  /** The text area for the manuscript's abstract. */
  private JTextArea my_ta_abstract;
  
  /** The text area for the manuscript's full text. */
  private JTextArea my_ta_full_text;
  
  /** The user that is filling out this submission form. */
  private User my_user;
  
  /** The access to the manuscript database. */
  private ManuscriptAccess my_manuscript_access;
  
  /** The access to the conference database. */
  private ConferenceAccess my_conference_access;
  
  /** The button used to unsubmit the manucript. */
  private JButton my_btn_unsubmit;

  
  /**
   * Initializes the panel with empty fields.
   * @param the_parent The main application window container.
   */
  public ManuscriptSubmissionPanel(final DisplayPanel the_parent) {
    super(the_parent);
    my_manuscript_access = MainPage.getDatabase().accessManuscript();
    my_conference_access = MainPage.getDatabase().accessConf();
  }
  
  /**
   * Initializes the panel with the Conference title filled out.
   * @param the_parent The main application window container.
   * @param the_c The conference that this paper will be submitted to.
   * @param the_u The user that is filling out this form.
   */
  public ManuscriptSubmissionPanel(final DisplayPanel the_parent,
                                   final Conference the_c,
                                   final User the_u) {
    this(the_parent);
    setConferenceFields(the_c);
    setUserFields(the_u);
  }
  
  /**
   * Initializes the panel with filled out fields.  Use this constructor if you
   * want to view a form that has been previously filled out.
   * @param the_parent The main application window container.
   * @param the_m The manuscript form that was filled out previously.
   */
  public ManuscriptSubmissionPanel(final DisplayPanel the_parent,
                                   final Manuscript the_m) {
    this(the_parent);
    setMode(MODE_EXISTING_FORM);
    populateFields(the_m);
    my_manuscript = the_m;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected String getFormTitle() {
    return "Manuscript Submission Form";
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected JPanel createFormPanel() {
    final JPanel panel_form = new JPanel();
    panel_form.setLayout(new BoxLayout(panel_form, BoxLayout.Y_AXIS));
    panel_form.setBackground(Standards.COLOR_BACKGROUND);
    panel_form.setBorder(Standards.BORDER_COMPOUND_FORM);
    
    panel_form.add(createColumnedPanel());
    panel_form.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    
    setUpTextFields(panel_form);
    setUpTextAreas(panel_form);
    
    return panel_form;
  }
  
  /**
   * Populates the manuscript submission form with text fields and their
   * respective labels.
   * @param the_panel The panel of the form.
   */
  private void setUpTextFields(final JPanel the_panel) {
    final JPanel panel_key_words = new JPanel();
    panel_key_words.setBackground(Standards.COLOR_BACKGROUND);
    panel_key_words.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_key_words = new JLabel("Key Words");
    panel_key_words.add(lbl_key_words, BorderLayout.CENTER);
    
    my_tf_key_words = new JTextField();
    my_tf_key_words.setToolTipText("Key words help search engines find your manuscript.");
    panel_key_words.add(my_tf_key_words, BorderLayout.SOUTH);
    
    final JPanel panel_manuscript_title = new JPanel();
    panel_manuscript_title.setBackground(Standards.COLOR_BACKGROUND);
    panel_manuscript_title.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_manuscript_title = new JLabel("Manuscript Title");
    panel_manuscript_title.add(lbl_manuscript_title, BorderLayout.CENTER);
    
    my_tf_manuscript_title = new JTextField();
    my_tf_manuscript_title.setToolTipText("The manuscript's full title (max 100 characters).");
    panel_manuscript_title.add(my_tf_manuscript_title, BorderLayout.SOUTH);

    the_panel.add(panel_key_words);
    the_panel.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    the_panel.add(panel_manuscript_title);
    the_panel.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
  }
  
  /**
   * Populates the manuscript submission form with text areas and their
   * respective labels.
   * @param the_panel The panel of the form.
   */
  private void setUpTextAreas(final JPanel the_panel) {
    final JPanel panel_abstract = new JPanel();
    panel_abstract.setBackground(Standards.COLOR_BACKGROUND);
    panel_abstract.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_abstract = new JLabel("Abstract");
    panel_abstract.add(lbl_abstract, BorderLayout.CENTER);
    
    my_ta_abstract = new JTextArea();
    my_ta_abstract.setToolTipText("A short summary of your manuscript.");
    my_ta_abstract.setRows(Standards.TEXT_AREA_MEDIUM_ROWS);
    my_ta_abstract.setWrapStyleWord(true);
    my_ta_abstract.setLineWrap(true);
    
    panel_abstract.add(createScrollPane(my_ta_abstract), BorderLayout.SOUTH);

    
    final JPanel panel_text = new JPanel();
    panel_text.setBackground(Standards.COLOR_BACKGROUND);
    panel_text.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_text = new JLabel("Text");
    panel_text.add(lbl_text, BorderLayout.CENTER);
    
    my_ta_full_text = new JTextArea();
    my_ta_full_text.setToolTipText("The full text of your manuscript.");
    my_ta_full_text.setRows(Standards.TEXT_AREA_LARGE_ROWS);
    my_ta_full_text.setWrapStyleWord(true);
    my_ta_full_text.setLineWrap(true);
    
    panel_text.add(createScrollPane(my_ta_full_text), BorderLayout.SOUTH);
    
    the_panel.add(panel_abstract);
    the_panel.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    the_panel.add(panel_text);
  }
  
  /**
   * Creates the columned portion of the form panel.
   * @return The columned panel.
   */
  private JPanel createColumnedPanel() {
    final JPanel panel_column_split = new JPanel();
    panel_column_split.setBackground(Standards.COLOR_BACKGROUND);
    panel_column_split.setLayout(new BoxLayout(panel_column_split, BoxLayout.X_AXIS));

    panel_column_split.add(createLeftColumnPanel());
    panel_column_split.add(Box.createHorizontalStrut(Standards.STRUT_LENGTH_LARGE));
    panel_column_split.add(createRightColumnPanel());
    
    return panel_column_split;
  }
  
  /**
   * Creates the left column of the columned panel.
   * @return The left column panel.
   */
  private JPanel createLeftColumnPanel() {
    final JPanel panel_left_column = new JPanel();
    panel_left_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_left_column.setLayout(new BoxLayout(panel_left_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_author = new JPanel();
    panel_author.setBackground(Standards.COLOR_BACKGROUND);
    panel_author.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_author = new JLabel("Author");
    
    my_tf_author = new JTextField();
    my_tf_author.setToolTipText("The submitting author's name.");
    my_tf_author.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    final JPanel panel_conference_name = new JPanel();
    panel_conference_name.setBackground(Standards.COLOR_BACKGROUND);
    panel_conference_name.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_conference = new JLabel("Conference");
    
    my_tf_conference_name = new JTextField();
    my_tf_conference_name.setToolTipText("The conference the manuscript "
                                         + "is being submitted to.");
    my_tf_conference_name.setColumns(Standards.TEXT_BOX_HALF_WIDTH);

    panel_left_column.add(panel_author);
    panel_author.add(lbl_author, BorderLayout.CENTER);
    panel_author.add(my_tf_author, BorderLayout.SOUTH);
    panel_left_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_left_column.add(panel_conference_name);
    panel_conference_name.add(lbl_conference, BorderLayout.CENTER);
    panel_conference_name.add(my_tf_conference_name, BorderLayout.SOUTH);
    
    return panel_left_column;
  }
  
  /**
   * Creates the right column of the columned panel.
   * @return The right column panel.
   */
  private JPanel createRightColumnPanel() {
    final JPanel panel_right_column = new JPanel();
    panel_right_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_right_column.setLayout(new BoxLayout(panel_right_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_email = new JPanel();
    panel_email.setBackground(Standards.COLOR_BACKGROUND);
    panel_email.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_email = new JLabel("Email");
    
    my_tf_email = new JTextField();
    my_tf_email.setToolTipText("The submitting author's email address.");
    my_tf_email.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    final JPanel panel_conference_category = new JPanel();
    panel_conference_category.setBackground(Standards.COLOR_BACKGROUND);
    panel_conference_category.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_conference_category = new JLabel("Conference Category");
    
    my_tf_conference_category = new JTextField();
    my_tf_conference_category.setToolTipText("The particular conference category that"
                                             + " this manuscript will be submitted under.");
    my_tf_conference_category.setColumns(Standards.TEXT_BOX_HALF_WIDTH);

    panel_right_column.add(panel_email);
    panel_email.add(lbl_email, BorderLayout.CENTER);
    panel_email.add(my_tf_email, BorderLayout.SOUTH);
    panel_right_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_right_column.add(panel_conference_category);
    panel_conference_category.add(lbl_conference_category, BorderLayout.CENTER);
    panel_conference_category.add(my_tf_conference_category, BorderLayout.SOUTH);
    
    return panel_right_column;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected JPanel createButtonsPanel() {
    final JPanel panel_buttons = new JPanel();
    panel_buttons.setBackground(Standards.COLOR_BACKGROUND);
    panel_buttons.setBackground(Standards.COLOR_BACKGROUND);
    panel_buttons.setAlignmentX(Component.LEFT_ALIGNMENT);
    
    my_btn_submit = new JButton("Submit");
    my_btn_submit.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        final boolean result = submitForm();
        if (result) {
          grantAuthorRole(my_user);
          JOptionPane.showMessageDialog(ManuscriptSubmissionPanel.this,
                                        "Form submitted successfully!");
          setMode(MODE_EXISTING_FORM);
        } else {
          JOptionPane.showMessageDialog(ManuscriptSubmissionPanel.this,
                                        "Something went wrong...");
        }
      }
    });
    
    my_btn_save_changes = new JButton("Save Changes");
    my_btn_save_changes.setVisible(false);
    my_btn_save_changes.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        final boolean result = editForm();
        if (result) {
          JOptionPane.showMessageDialog(ManuscriptSubmissionPanel.this,
                                        "Form edited successfully!");
        } else {
          JOptionPane.showMessageDialog(ManuscriptSubmissionPanel.this,
                                        "Unable to edit paper.");
        }
      }
    });
    
    my_btn_unsubmit = new JButton("Unsubmit");
    my_btn_unsubmit.setVisible(false);
    my_btn_unsubmit.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        my_manuscript_access.deleteManuscript(my_manuscript.getID()); 
        JOptionPane.showMessageDialog(ManuscriptSubmissionPanel.this,
                                      "Form deleted! D:");
      }
    });
    
    final JButton btn_cancel = new JButton("Cancel");
    btn_cancel.addActionListener(new ActionListener() {
      /** The action to be performed.
       * Removes the form from view. */
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        getDisplayStack().removeFromStack();
      }
    });
    
    panel_buttons.add(my_btn_submit);
    panel_buttons.add(my_btn_save_changes);
    panel_buttons.add(my_btn_unsubmit);
    panel_buttons.add(btn_cancel);
    return panel_buttons;
  }
  
  


  /**
   * Completes the Manuscript Submission form and submits it to the database.
   * @return true if the form was successfully submitted; false otherwise.
   */
  private boolean submitForm() {
    final Manuscript m = inputToManuscript();
    my_manuscript = m;
    if (isPastSubmissionDeadline()) {
      JOptionPane.showMessageDialog(this, ERROR_DEADLINE);
      return false;
    }
    return my_manuscript_access.createManuscript(m);
    //TODO send the manuscript to the Program Chair
  }
  
  /**
   * Edits the Manuscript and submits the changes to the database.
   * @return true if the form was successfully submitted; false otherwise.
   */
  private boolean editForm() {
    final Manuscript m = inputToManuscript();
    m.setID(my_manuscript.getID());
    if (isPastSubmissionDeadline()) {
      JOptionPane.showMessageDialog(this, ERROR_DEADLINE);
      return false;
    }
    return my_manuscript_access.editManuscript(m);
  }
  
  /**
   * Returns whether or not the current date is past the submission deadline.
   * @return true if the time is currently past submission deadline; false otherwise.
   */
  private boolean isPastSubmissionDeadline() {
    return new Date().after(my_conference.getSubmissionDeadline());
  }
  
  /**
   * Converts form input into a Manuscript object.
   * @return The Manuscript.
   */
  private Manuscript inputToManuscript() {
    long id = 0;
    if (my_manuscript != null) {
      id = my_manuscript.getID();
    }
    long conf_id = 0;
    if (my_manuscript != null) {
      conf_id = my_manuscript.getConferenceID();
    } else if (my_conference != null) {
      conf_id = my_conference.getID();
    }
    int status = Manuscript.STATUS_UNDECIDED;
    if (my_manuscript != null) {
      status = my_manuscript.getDecisionStatus();
    }
    final List<String> authors = parseString(my_tf_author.getText());
    final List<String> key_words = parseString(my_tf_key_words.getText());
    final List<String> categories = parseString(my_tf_conference_category.getText());
    List<Long> review_ids = new ArrayList<Long>();
    if (my_manuscript != null) {
      review_ids = my_manuscript.getReviewIDs();
    }
    long rec_id = -1;
    if (my_manuscript != null) {
      rec_id = my_manuscript.getRecommendationID();
    }
    final Manuscript m = new Manuscript(id,
                                        my_tf_manuscript_title.getText(),
                                        authors,
                                        my_tf_email.getText(),
                                        conf_id,
                                        key_words,
                                        categories,
                                        my_ta_abstract.getText(),
                                        my_ta_full_text.getText(),
                                        status,
                                        review_ids,
                                        rec_id);
    return m;
  }
  
  /**
   * Populates the form using a previously filled out form.
   * @param the_m The manuscript that was previously submitted.
   */
  private void populateFields(final Manuscript the_m) {
    lockInText(my_tf_author, the_m.getSubmittingAuthor());
    lockInText(my_tf_email, the_m.getEmail());
    setConferenceFields(my_conference_access.getConference(the_m.getConferenceID()));
    my_tf_conference_category.setText(convertStringListToString(the_m.getCategories()));
    my_tf_key_words.setText(convertStringListToString(the_m.getKeyWords()));
    my_tf_manuscript_title.setText(the_m.getTitle());
    my_ta_abstract.setText(the_m.getAbstract());
    my_ta_full_text.setText(the_m.getDirectoryPath());
  }
  
  /**
   * Parses the input String from JTextField and returns a List<String>.
   * @param the_str The input from a JTextField.
   * @return A List<String>.
   */
  private List<String> parseString(final String the_str) {
    final String[] list = the_str.split("[,;]");
    final List<String> other_list = new ArrayList<String>(list.length);
    for (String str : list) {
      other_list.add(str);
    }
    return other_list;
  }
  
  /**
   * A convenience method for converting a list of Strings into a single
   * String with all values.
   * @param the_list The list to be converted.
   * @return The String that looks nice in a JTextField.
   */
  private String convertStringListToString(final List<String> the_list) {
    final Iterator<String> itr = the_list.iterator();
    final StringBuilder sb = new StringBuilder();
    if (itr.hasNext()) {
      sb.append(itr.next());
      while (itr.hasNext()) {
        sb.append(", ");
        sb.append(itr.next());
      }
    }
    return sb.toString();
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected void setMode(final boolean the_bool) {
    super.setMode(the_bool);
    if (my_btn_unsubmit != null) {
      my_btn_unsubmit.setVisible(the_bool);
    }
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  public String getPanelLabel() {
    return "Manuscript";
  }
  
  /**
   * Sets the parameters dependent on the user filling out the form.
   * @param the_user The User data object.
   */
  private void setUserFields(final User the_user) {
    my_user = the_user;
    lockInText(my_tf_author, the_user.getFullName());
    lockInText(my_tf_email, the_user.getEmail());
  }
  
  /**
   * Sets the parameters dependent on the conference that the user is filling
   * out the form for.
   * @param the_conference The Conference data object.
   */
  private void setConferenceFields(final Conference the_conference) {
    my_conference = the_conference;
    lockInText(my_tf_conference_name, the_conference.getTitle());
  }
  
  /**
   * Sets the text of the text field and then makes it uneditable.
   * @param the_field The text component to set the text for.
   * @param the_str   The String to be displayed.
   */
  private void lockInText(final JTextComponent the_field, final String the_str) {
    the_field.setText(the_str);
    the_field.setEditable(false);
  }
  
  /**
   * Attempts to grant the author status to the user.
   * @param the_user The User data object.
   */
  private void grantAuthorRole(final User the_user) {
    final List<Role> roles = the_user.getRoles();
    for (Role r : roles) {
      if (r.getRoleID() == Author.ROLE_ID) {
        return;
      }
    }
    final List<Long> list = new ArrayList<Long>();
    list.add(my_manuscript.getID());
    the_user.addRole(new Author(0, my_user, my_conference.getID(), list));
  }
  
  /**
   * Locks or unlocks the form by setting every field's editable status.
   * @param the_bool true if the form should be uneditable; false otherwise.
   */
  protected void lockForm(final boolean the_bool) {
    my_ta_abstract.setEditable(!the_bool);
    my_ta_full_text.setEditable(!the_bool);
    //my_tf_author.setEditable(!the_bool);
    my_tf_conference_category.setEditable(!the_bool);
    //my_tf_conference_name.setEditable(!the_bool);
    //my_tf_email.setEditable(!the_bool);
    my_tf_key_words.setEditable(!the_bool);
    my_tf_manuscript_title.setEditable(!the_bool);
  }
  
}
